<template>
    <div>

    <el-upload
            ref="upload"
            :action="computedAction"
            :data="data"
            :accept="typeof accept == 'function'? accept(): accept"
            :limit="limit==1 ? (limitOneUpdateModel? null: limit): limit"
            :disabled="disabled"
            :name="name"
            :headers="headers"
            :file-list="localFileList"
            :show-file-list="showFileList"
            :list-type="listType"
            :auto-upload="autoUpload"
            :multiple="multiple"
            :on-success="onSuccess"
            :on-change="onChange"
            :on-error="onError"
            :on-exceed="onExceed"
            :on-remove="onRemove"
            :on-preview="onPreview"
            :before-upload="beforeUpload">
        <template v-if="listType == 'picture-card'">
            <el-image v-if="limit ==1 && accept && accept.indexOf('image')>=0 && !showFileList && localFileList.length > 0"
                    class="g-height100 g-width100"
                    :src="limitOneImageUrl"
                    fit="fit"></el-image>
            <i v-else :class="(limit ==1 && loading && !showFileList) ? 'el-icon-loading': 'el-icon-plus'" ></i>
        </template>
        <template v-else>
            <el-button size="small" :loading="(limit ==1 && loading && !showFileList)" type="primary">点击上传</el-button>
        </template>
    </el-upload>
        <!-- 图片预览 -->
        <el-dialog :visible.sync="dialogVisible">
            <img width="100%" :src="dialogImageUrl" alt="">
        </el-dialog>
    </div>
</template>

<script>
    import {isArray} from '../../tools/ArrayTools.js'
    import StorageTools from '../../tools/StorageTools'
    import {isString, endWithAny} from '../../tools/StringTools.js'
    export default {
        name: 'FileUpload',
        props: {
            // url地址 String 类型只支持一个url地址
            // 支持两种类型，初始化已上传的地址，其它如果是数组，则数组元素是String类型
            // 如果不自动上传时，String 可能会是文件对象本身
            value: {
                type: [String,Array,Object]
                //required: true
            },
            // 上传文件的表单名称
            name:{
                type: String,
                default: 'file'
            },
            // 是否禁用
            disabled:{
                type:Boolean,
                default:false
            },
            // 上传时附带的额外参数
            data: {
                type: Object
            },
            // 接受上传的文件类型,多个以分号分隔
            //image/jpeg image/*
            accept: {
                type: [String,Function]
            },
            // 最大允许上传个数,最少为1
            limit: {
                type: Number,
                default: 1
            },
            // 上传文件大小限制，支持kb，mb，gb后缀
            limitSize:{
                type: String
            },
            // 最大上传个数为1时启动上传更新模式，如果不启用必须先删除已存在的才能再上传
            limitOneUpdateModel: {
                type: Boolean,
                default: true
            },
            // 是否显示已上传的文件列表
            showFileList: {
                type: Boolean,
                default: true
            },
            // 已上传的文件列表{name:'',url:''}
            /*fileList: {
                type: Array,
                default: function () {
                    return []
                }
            },*/
            // text/picture/picture-card
            listType: {
                type: String,
                default: 'picture-card'
            },
            multiple: {
                type: Boolean,
                default: false
            },
            autoUpload: {
                type: Boolean,
                default: true
            },
            // 上传成功回调 文件上传成功时的钩子
            onSuccessCallback: {
                type: Function
            },
            // 文件列表移除文件时的钩子
            onRemoveCallback:  {
                type: Function
            },
            onPreviewCallback:  {
                type: Function
            },
            // 数据响应值格式化
            responseValueFormat:{
                type: Function
            },
            // 上传url
            action: {
                type: [String,Function]
            },
            nullActionMessage:{
                type:  String,
                default: '上传的url不能为空'
            }
        },
        computed: {
            limitOneImageUrl (){
                let r = ''
                if(this.limit ==1 && this.localFileList.length > 0){
                    r = this.localFileList[0].url
                }
                return r
            },
            computedAction(){
                if(typeof this.action == 'function'){
                    let url = this.action()
                    if(url === false){
                        return ''
                    }else{
                        return url
                    }
                }else {
                    if(!this.action){
                        return this.$baseURL.file + '/file/cloudstorage/upload'
                    }
                }
                return this.action
            }
        },
        data () {
            return {
                headers:{
                    Authorization: null
                },
                // 上传的加载状态，暂时没有想好怎么用
                loading: false,
                localValue: this.value,
                // filelist 元素内容为{name:'',url:''}
                originFileList: [],
                localFileList: [],
                dialogVisible: false,
                dialogImageUrl: null
            }
        },
        created() {
            // 初始化文件列表
            this.generateLocalFileList(this.value)
        },
        mounted () {

            this.headers.Authorization = StorageTools.sessionGet('Authorization')
        },

        methods: {
            loadingStart(){
                this.loading = true
                this.$emit('loading',true)
            },
            loadingEnd(){
                this.loading = false
                this.$emit('loading',false)
            },
            submit () {
                this.$refs.upload.submit()
            },
            // responseData是数据实体并不是axios的response
            onSuccess (responseData, file, fileList) {
                this.loadingEnd()
                if (this.onSuccessCallback && typeof this.onSuccessCallback === 'function') {
                    this.onSuccessCallback(responseData, file, fileList)
                }
            },
            // 上传失败 文件上传失败时的钩子
            // error 是数据实体并不是axios的response
            // fileList 不包括上传失败的文件
            onError (error, file, fileList) {
                if (error) {
                    this.$message.error('文件上传失败，请稍候再试')
                    //this.clearFiles()
                }
                this.loadingEnd()
            },
            // 上传文件之前的钩子，参数为上传的文件，若返回 false 或者返回 Promise 且被 reject，则停止上传。
            beforeUpload (file) {
                this.headers.Authorization = StorageTools.sessionGet('Authorization')
                if(this.limitSize){
                    let limitSize = this.limitSize
                    let isLt = true
                    if (endWithAny(this.limitSize, 'KB', true)) {
                        isLt = file.size / 1024  < parseInt(limitSize.replace('KB',''))
                    }else if (endWithAny(this.limitSize, 'MB', true)) {
                        isLt = file.size / 1024 / 1024  < parseInt(limitSize.replace('MB',''))
                    }else if (endWithAny(this.limitSize, 'GB', true)) {
                        isLt = file.size / 1024 / 1024 / 1024  < parseInt(limitSize.replace('MB',''))

                    }else {
                        isLt = file.size   < limitSize
                    }
                    if(isLt == false){
                        this.$message.error('上传文件大小不能超过 '+ this.limitSize +'!');
                        return false
                    }
                }
                // 判断url是否为空
                if(this.action){
                    let url = this.action()
                    if (url === false) {
                        if(this.nullActionMessage && this.nullActionMessage != ''){
                            this.$message.error(this.nullActionMessage)
                        }
                        return false
                    }
                }
                this.loadingStart()
            },
            // 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
            onChange (file, fileList) {

                if(this.limit == 1){
                    this.localFileList.splice(0,this.localFileList.length,file)

                    let list = [file]
                    this.emit(list)
                    this.$emit('onChange',file)
                }else{
                    this.emit(fileList)
                    this.$emit('onChange',fileList)
                }

            },
            // 文件列表移除文件时的钩子
            // fileList 删除之后的文件列表
            onRemove (file, fileList) {
                this.emit(fileList)
                if (this.onRemoveCallback && typeof this.onRemoveCallback === 'function') {
                    this.onRemoveCallback(file, fileList)
                }
            },
            // 文件超出个数限制时的钩子
            // files 本次选择的文件
            // fileList总共的文件
            onExceed (files, fileList) {
                this.loading = false
                this.$message.error('文件超出限制个数:' + this.limit)
            },
            // 预览文件
            onPreview (file){
                if (this.onPreviewCallback && typeof this.onPreviewCallback === 'function') {
                    this.onPreviewCallback(file)
                }else if(this.accept && this.accept.indexOf('image') >=0 || endWithAny(file.url,['jpg','png','gif'],true)){
                    this.dialogImageUrl = file.url
                    this.dialogVisible = true
                }else{
                    this.$message.info('暂不支持预览功能')
                }
            },
            clearFiles () {
                this.$refs.upload.clearFiles()
            },
            // 重新生成已上传文件列表
            generateLocalFileList(value){
                if(!value || value.length == 0) {
                    this.localFileList = []
                    return
                }
                // 初始化列表
                if(this.localFileList.length == 0){
                    let tempLocalFileList = []
                    // 不是字符串就是数据，如果value类型有变动这里需要变动
                    if (isString(value)) {
                        tempLocalFileList.push({
                            name: value.substring(value.lastIndexOf('/') + 1),
                            url: value
                        })
                    }else if (isArray(value)) {
                        value.forEach((item)=>{
                            tempLocalFileList.push({
                                name: item.substring(item.lastIndexOf('/') + 1),
                                url: item
                            })
                        })
                    }

                    this.localFileList = tempLocalFileList
                }else{
                   // 本代码片段主要功能以value数据为准
                    // 将value中多于localFileList的元素添加
                    // 将localFileList多于value 的删除

                    let tempValue = []
                    // 不是字符串就是数据，如果value类型有变动这里需要变动
                    if (isString(value)) {
                        tempValue.push(value)
                    }else if (isArray(value)) {
                        tempValue = value
                    }
                    if(tempValue.length > this.limit){
                        this.$message.error('文件超出限制个数:' + this.limit)
                        this.$emit('input', value)
                        return
                    }
                    let self = this
                    let localFileListDeleteIndex = []
                    let tempValueAddIndex = []
                    this.localFileList.forEach((item,index)=>{

                        if (item.status == 'success'&&item.response && (!item.url || item.url.indexOf('blob:') == 0)) {
                            item.url = item.response.url
                            this.localFileList.splice(index,1,item)
                        }
                        // tempValue 中是否包含item
                        let isTempValueIncludeItem = tempValue.some((val)=>{
                            return item.url == val
                        })
                        if (!isTempValueIncludeItem&&item.status == 'success') {
                            localFileListDeleteIndex.push(index)
                        }
                    })
                    tempValue.forEach((val,index)=>{
                        let isLocalFileListIncludeVal = self.localFileList.some((item)=>{
                            return item.status == 'success' && val == item.url
                        })
                        if (!isLocalFileListIncludeVal) {
                            tempValueAddIndex.push(index)
                        }
                    })
                    for(let i=localFileListDeleteIndex.length-1;i >= 0;i--){
                        this.localFileList.splice(localFileListDeleteIndex[i],1)
                    }
                    tempValueAddIndex.forEach((val)=>{
                        this.localFileList.push({
                            name: tempValue[val].substring(tempValue[val].lastIndexOf('/') + 1),
                            url: tempValue[val]
                        })
                    })

                    if(this.localFileList.length != tempValue.length){
                        this.emit(this.localFileList)
                    }
                }
            },
            // 内部调用
            getFileUploadUrl(file){

                if (file.status == 'success') {
                    let url = file.response ? (this.responseValueFormat? this.responseValueFormat(file.response): file.response.url) : file.url
                    if(url.indexOf('blob:') == 0){
                        return null
                    }else{
                        return url
                    }
                }
                // 不自动提交是，不再获取url
                if(this.autoUpload == false){
                    return file
                }
                return null
            },
            emit(originFileList){
                this.localFileList = originFileList

                if (originFileList.length == 0){
                    if (isString(this.localValue)) {
                        this.$emit('input', null)
                    }else if (isArray(this.localValue)) {
                        this.$emit('input', [])
                    }
                    return
                }
                // this.limit 必须大于0
                if(this.limit == 1){
                    let file = originFileList[0]
                    let url = this.getFileUploadUrl(file)
                    if(url){
                        this.$emit('input', url)
                    }
                }else{
                    let fileListTemp = []
                    let self = this
                    originFileList.forEach((item) => {
                        let url = self.getFileUploadUrl(item)
                        if(url){
                            fileListTemp.push(url)
                        }
                    })
                    this.$emit('input', fileListTemp)
                }
            },
            httpRequest(){

            }
        },
        watch: {

            value (val) {
                this.localValue = val
            },
            localValue(val){
                this.generateLocalFileList(val)
            }

        }
    }
</script>

<style scoped>

</style>
